/*
    This is a set of libraries to assist in OpenGl and Other Applications
    Copyright (C) 2008  The Modular Engine Team

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INTERFACEOBJECT_H
#define INTERFACEOBJECT_H

#undef CLASSDECL
#ifdef INTERFACEMODULE
	#define CLASSDECL __declspec(dllexport)
#else
	#pragma comment( lib, "InterfaceModule.lib" )
	#define CLASSDECL __declspec(dllimport)
#endif

#include "math.h"
#include <deque>
using namespace std;

namespace ModularEngine
{
	class IMKeyInput
	{
	public:
		/// Which Key Changed
		unsigned char mKey;

		/// State of the key change

		/// true = down
		/// false = up
		bool mState;
	};

	enum IMMouseButtons
	{
		IMM_LEFT,
		IMM_RIGHT,
		IMM_MIDDLE
	};

	class IMMouseInput
	{
	public:
		/// Which Mouse Button is Changed
		unsigned char mButton; 
		
		/// State of the button

		/// true = down
		/// false = up
		bool mState;

		/// Current Cursor Position
		Vector2d mvPosition;
	};

	class CLASSDECL IMFunctor
	{
	public:
		virtual void operator () () = 0;

	};

	class CLASSDECL IMEvent
	{
		/// Types of 
		enum IME_TYPES
		{
			IME_FUNCTION,
			IME_SCRIPT,
			IME_FUNCTOR
		};
		unsigned int mType;
		void *mpFunc;
		char *mpScript;
		IMFunctor *mpFunctor;
	public:
		/// Initializes Event Trigger
		IMEvent();
		/// Overload if user passes console script
		void operator = (char *pScript);
		/// Overload if user passes single function to event
		template <class Func> void operator = (Func pFunc);
		/// Overload if user passes a functor.
		void operator = (IMFunctor *pFunctor);

		/// Call functor or function
		void operator () ();
	};

	class CLASSDECL InterfaceObject
	{
		
	public:
		/// Events For Interface Objects
		struct
		{
			IMEvent onDestroy;				// Implemented
			IMEvent onDraw;					// Implemented
			IMEvent onGainFocus;
			IMEvent onHide; 
			IMEvent onInitialize;			// Implemented
			IMEvent onKeyDown;				// Implemented
			IMEvent onKeyUp;				// Implemented
			IMEvent onLoseFocus;			
			IMEvent onMouseDown;			// Implemented
			IMEvent onMouseHover;			
			IMEvent onMouseMove;			// Implemented
			IMEvent onMouseUp;				// Implemented
			IMEvent onMove; 
			IMEvent onShow;
			IMEvent onValueChange;
		} Events;

	private:
		/// Child Elements:
		deque<InterfaceObject *> mvChildren;

	public:

		/// Value of the Object
		char *mpValue;
		/// Name of the Object (Derived from the XML)
		char *mpName;
		/// Is object enabled?
		bool mEnabled;
		/// Is the object visible?
		bool mVisible;
		/// Is the object movable? (Windows Only)
		bool mMovable;
		/// Type of object (for reference)
		unsigned int m_nType;
		/// Object's 2D Position
		Vector2d mvPosition;
		/// Object's Width and Height
		Vector2d mvDimensions;
		/// Parent object if any
		InterfaceObject *mpParent;

	public:
		/// Intialize the object;
		InterfaceObject();

		/// Destroy the object.
		~InterfaceObject();

		/// Draw the Interface Object
		void Draw();

		/// Intialize the Object

		/// By default this does nothing, but might if overloaded.
		void Initialize();

		/// Send Mouse Button Info
		void SendMouseButton(IMMouseInput rMouse);

		/// Send Mouse Movement Info
		void SendMouseMovement(IMMouseInput rMouse);

		/// Give Keyboard Input
		void SendKeyInput( IMKeyInput rKey );

		/// Add a child:
		void AddChild(InterfaceObject *rObject);

		/// Find Child

		/// Returns True if rObject is one of the children.
		bool FindChild(InterfaceObject *rObject);


	};
}


#endif // #ifndef INTERFACEOBJECT_H